/*
 * ProductDAO.java
 *
 * Created on March 29, 2007, 1:11 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */


package edu.byu.isys413.samlam;
import java.util.*;
import java.io.*;
import java.sql.*;

/**
 * database access object for ravenue sources
 */
    public abstract class ProductDAO 
    {
   

    /** Creates a new instance of ProductDAO */
    public ProductDAO() {
    }
  
    /////////////////////////////////
    ///   CREATE
    /**
     * Create
     * @return ProductDAO create
     */
    public abstract  Product create();
    /////////////////////////////////////
    ///   READ
    /**
     * read
     * @param id ProductDAO id
     * @throws edu.byu.isys413.samlam.DataException exception
     * @throws edu.byu.isys413.samlam.ConnectionPoolException exception
     * @return Product DAO return
     */
    public Product read(String id) throws DataException,ConnectionPoolException
    {
        
        try
        {
            Connection conn = ConnectionPool.getInstance().get();
            Product prod = (Product)read(id,conn);
            ConnectionPool.getInstance().release(conn);
            return prod;
        }
        catch (SQLException e)
        {
            // rollback
            throw new DataException("SQL error from read 1", e);
        }
        catch (ConnectionPoolException e)
        {
            throw new ConnectionPoolException("Connection pool error in read 1", e);
        }
    }
    public Product read(String id, Connection conn) throws SQLException, DataException, ConnectionPoolException
    {

        if(Cache.getInstance().containsKey(id))
        {
            Product prod = (Product)Cache.getInstance().get(id);
            return prod;
         }      
         try
         {        
           PreparedStatement stmt = conn.prepareStatement("SELECT * FROM Product WHERE productid=?");
           stmt.setString(1,id);
           ResultSet rs =  stmt.executeQuery();
           
           ConnectionPool.getInstance().release(conn);
            
            if (rs.next())
            {
                Product prod = (Product)Cache.getInstance().get(id);
                prod.setPrice(rs.getDouble("price"));
                Cache.getInstance().put(id,prod);
                prod.setObjectAlreadyInDB(true);
                //prod.setIndb(true);
                stmt.close();
                return prod;
               

            }
            else
            {
                throw new DataException("Product was not found in the database.");
            }
           
            }
         catch (ConnectionPoolException e)
         {
                throw new ConnectionPoolException("Could not retrieve a connection from the database", e);
            
          }catch (SQLException e)
          {
                throw new DataException("SQL error", e);
            }
    }
    //////////////////////////////////
    ///   UPDATE
    /**
     * ProductDAO save
     * @param prod Save product
     * @throws edu.byu.isys413.samlam.DataException exception
     * @throws edu.byu.isys413.samlam.ConnectionPoolException exception
     */
    public synchronized void save(Product prod) throws DataException,ConnectionPoolException 
    {
        System.out.println("in save of product DAO"); 
        try 
          {
            Connection conn = ConnectionPool.getInstance().get();
            save(prod,conn);
            ConnectionPool.getInstance().release(conn);
          }
          catch (SQLException e)
          {
            //rollback
            throw new DataException("Could not retrieve record for id=" + prod.getId(), e);
          }
          catch (ConnectionPoolException e)
          {
            e.printStackTrace();
        }
        
        // release the connection back to the pool
        return;
    }
     synchronized void save(Product prod, Connection conn) throws SQLException, DataException, ConnectionPoolException 
    {
        // check the dirty flag in the ProductBO.  if it is dirty, 
        // run update or insert
        if (prod.isDirty())
        {
            if(prod.isObjectAlreadyInDB()){
               update(prod, conn);
            }
            else
            {
               insert(prod, conn);
            }
            prod.setDirty(false);
        Cache.getInstance().touch(prod.getId());
     
        }
        
    }
 private synchronized void update(Product prod, Connection conn) throws SQLException, DataException, ConnectionPoolException 
 {
        PreparedStatement stmt = conn.prepareStatement("UPDATE Product SET price = ? WHERE productid=? ");
        stmt.setDouble(1,prod.getPrice());
        stmt.setString(2,prod.getId());
        stmt.execute();
        stmt.close();
        ConnectionPool.getInstance().release(conn);
    }
     
    /**
     * This method is really a part of save(bo, conn) above.  It could be
     * embedded directly in it, but I've separated it into it's own method
     * to isolate the SQL insert statement and make it more readable.  But
     * logically, it's really just a part of save.
     */
    private synchronized void insert(Product prod, Connection conn) throws SQLException, DataException, ConnectionPoolException 
    {
        // do the insert SQL statement
          Statement stmt = conn.createStatement();
        stmt.executeUpdate("INSERT INTO Product VALUES ('"+prod.getId()+"', "+prod.getPrice()+")");
        stmt.close();
        
        // tell the RevenueSourceDBO that it's now in the db (so we call update next time not insert)
        prod.setDirty(false);
        ConnectionPool.getInstance().release(conn);
    }
}